﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Jayden.Dll.Cards;
using Jayden.Dll.Cards.Poker;
using Jayden.Dll.Cards.Poker.Enums;
using Jayden.Dll.Cards.Poker.PokerStars;
using Jayden.Dll.Core;
using Jayden.Dll.Core.Persistence;

namespace PokerTest
{
	class Program
	{


		static void ImportHandHistoryToDatabase(string[] args)
		{

			string handHistoryPath = @"C:\Users\Jonathan\AppData\Local\PokerStars.BE\HandHistory\jonv11\";
			string handFilter = "*No Limit Hold'em*.txt";


			if (File.Exists("database.db"))
				File.Delete("database.db");

			Configuration configuration = new Configuration("Configuration.xml");
			UnitOfWork uow = new UnitOfWork(configuration.GetConfiguration("UnitOfWork"));
			/*
			WebClient client = new WebClient();
			string jsonResponse = client.DownloadString("http://www.google.com/ig/calculator?hl=en&q=1USD=?EUR");
			JsonObject response = JsonHelper.ParseJson(jsonResponse) as JsonObject;
			string valueString = (response["rhs"] as JsonString).Value;
			string[] valueArray = valueString.Split(' ');
			double usdRatio = double.Parse(valueArray[0], CultureInfo.InvariantCulture);
			System.Console.WriteLine("1 USD = " + usdRatio + " EUR.");
			*/

			string[] files = Directory.GetFiles(handHistoryPath, handFilter);
			int count = 0;
			int countLines = 0;

			Dictionary<string, TexasHoldemPlayerStatistics> statistics = new Dictionary<string, TexasHoldemPlayerStatistics>();
			HashSet<string> players = new HashSet<string>();
			HashSet<string> tables = new HashSet<string>();
			HashSet<string> handReferences = new HashSet<string>();
			List<TexasHoldemHandSummaryLegacy> summaries = new List<TexasHoldemHandSummaryLegacy>();
			List<TexasHoldemHandSummary> commited = new List<TexasHoldemHandSummary>();

			DateTime start = DateTime.Now;

			Regex filenameRegex = new Regex(@"(?<Date>\d+) (?<TableName>.+) \- (?<SmallBlind>.+)\-(?<BigBlind>.+) \- (?<Currency>.+) No Limit Hold'em");
			Regex filenameTournamentRegex = new Regex(@"(?<Date>\d+) T(?<TournamentId>\d+) No Limit Hold'em (?<BuyIn>.+)");
			ulong session = 0;
			foreach (string filepath in files)
			{
				try
				{
					string filename = Path.GetFileNameWithoutExtension(filepath);

					Match filenameMatch = filenameRegex.Match(filename);
					if (!filenameMatch.Success)
					{
						filenameMatch = filenameTournamentRegex.Match(filename);
						if (!filenameMatch.Success)
							throw new Exception("Invalid filename pattern.");
					}
					System.Console.WriteLine((count * 100.0 / files.Length).ToString("0.00") + "% (lines:" + countLines + ", tables:" + tables.Count + ", players:" + players.Count + ", hands:" + summaries.Count + ")");
					count++;
					string[] lines = File.ReadAllLines(filepath);
					countLines += lines.Length;
					string tournamentId = null;
					if (filenameMatch.Groups["TournamentId"] != null)
						tournamentId = filenameMatch.Groups["TournamentId"].Value;
					List<TexasHoldemHandSummaryLegacy> s = new List<TexasHoldemHandSummaryLegacy>(HistoryReader.Read(lines));
					tables.Add(s[0].TableName);
					foreach (TexasHoldemHandSummaryLegacy table in s)
					{
						table.ComputeStatistics(uow, statistics, true, false);
						TexasHoldemHandSummary summary = new TexasHoldemHandSummary(uow);
						summary.TournamentId = tournamentId;
						summary.Session = session;
						summary.HandDateTime = table.DateTime;
						summary.BigBlind = table.BigBlind;
						summary.ButtonNumber = table.ButtonNumber;
						summary.Currency = table.Currency;
						summary.HandReference = table.HandReference;
						summary.ProviderName = table.ProviderName;
						summary.Rake = table.Rake;
						summary.SeatCount = table.SeatCount;
						summary.PlayerCount = (uint)table.Seats.Count;
						summary.WentToShowdown = table.Showdown;
						summary.SmallBlind = table.SmallBlind;
						summary.TableName = table.TableName;
						summary.TotalPot = table.TotalPot;
						summary.HandDateTime = table.DateTime;
						summary.HandDateTime = table.DateTime;
						summary.LastStreet = table.Street;
						if (table.HasFlop)
						{
							summary.FlopCards = new CardList(table.CommunityCards[0], table.CommunityCards[1], table.CommunityCards[2]);
							if (table.HasRiver)
							{
								summary.TurnCard = table.CommunityCards[3];
								if (table.HasRiver)
									summary.RiverCard = table.CommunityCards[4];
							}
						}

						uow.MarkNew(summary);
						commited.Add(summary);

						handReferences.Add(table.HandReference);
						foreach (TexasHoldemHandSummaryLegacy.SeatInformation seat in table.Seats)
							players.Add(seat.PlayerName);
					}
					summaries.AddRange(s);
					session++;
				}
				catch (Exception e)
				{
					System.Console.WriteLine("Unable to process file " + filepath);
				}
			}

			uow.Commit();

			System.Console.WriteLine("Hands and statistics commited !");


			System.Console.WriteLine("Writing actions and seats ...");

			for (int c = 0; c < summaries.Count; c++)
			{
				TexasHoldemHandSummaryLegacy table = summaries[c];
				TexasHoldemHandSummary summary = commited[c];
				foreach (TexasHoldemHandSummaryLegacy.SeatInformation seat in table.Seats)
				{
					TexasHoldemPlayerHandSummary player = new TexasHoldemPlayerHandSummary(uow);
					player.HandId = summary.TexasHoldemHandSummaryId;
					player.HandSummary = summary;
					player.PlayerName = seat.PlayerName;
					player.PlayerStack = seat.PlayerStack;
					player.Position = (uint)table.GetPosition(seat.PlayerName);
					if (table.Seats.Count > 2)
					{
						if (player.Position == 0)
							table.IsSmallBlind(player.PlayerName);
						if (player.Position == 1)
							table.IsBigBlind(player.PlayerName);
						if (player.Position == 2)
							table.IsUnderTheGun(player.PlayerName);
					}
					else
					{
						if (player.Position == 0)
							table.IsBigBlind(player.PlayerName);
						if (player.Position == 1)
							table.IsSmallBlind(player.PlayerName);
					}
					player.SeatNumber = (uint)seat.Number;
					if (table.FoldStreet.ContainsKey(seat.PlayerName))
						player.FoldStreet = table.FoldStreet[seat.PlayerName];
					else
						player.FoldStreet = table.Street;
					player.PlayerBalance = table.GetBalance(seat.PlayerName);
					player.PlayerWon = 0;
					foreach (KeyValuePair<string, ulong> pair in table.Winnings)
						if (pair.Key.Equals(seat.PlayerName))
							player.PlayerWon += pair.Value;
					if (table.HoleCards.ContainsKey(seat.PlayerName))
					{
						player.PlayerCards = table.HoleCards[seat.PlayerName];
						player.PlayerFinalHand = PokerHighHand.GetBestHand(player.PlayerCards, table.CommunityCards);
					}
					uow.MarkNew(player);
				}
				uint actionNumber = 0;
				if (table.PreFlopActions != null)
					foreach (TexasHoldemHandSummaryLegacy.ActionInformation action in table.PreFlopActions)
					{
						TexasHoldemHandAction thhaction = new TexasHoldemHandAction(uow);
						thhaction.Street = PokerStreetType.PreFlop;
						thhaction.ActionNumber = actionNumber++;
						thhaction.ActionType = action.ActionType;
						thhaction.Amount = action.Amount;
						thhaction.HandId = summary.TexasHoldemHandSummaryId;
						thhaction.PlayerName = action.PlayerName;
						uow.MarkNew(thhaction);
					}
				if (table.FlopActions != null)
					foreach (TexasHoldemHandSummaryLegacy.ActionInformation action in table.FlopActions)
					{
						TexasHoldemHandAction thhaction = new TexasHoldemHandAction(uow);
						thhaction.Street = PokerStreetType.Flop;
						thhaction.ActionNumber = actionNumber++;
						thhaction.ActionType = action.ActionType;
						thhaction.Amount = action.Amount;
						thhaction.HandId = summary.TexasHoldemHandSummaryId;
						thhaction.PlayerName = action.PlayerName;
						uow.MarkNew(thhaction);
					}
				if (table.TurnActions != null)
					foreach (TexasHoldemHandSummaryLegacy.ActionInformation action in table.TurnActions)
					{
						TexasHoldemHandAction thhaction = new TexasHoldemHandAction(uow);
						thhaction.Street = PokerStreetType.Turn;
						thhaction.ActionNumber = actionNumber++;
						thhaction.ActionType = action.ActionType;
						thhaction.Amount = action.Amount;
						thhaction.HandId = summary.TexasHoldemHandSummaryId;
						thhaction.PlayerName = action.PlayerName;
						uow.MarkNew(thhaction);
					}
				if (table.RiverActions != null)
					foreach (TexasHoldemHandSummaryLegacy.ActionInformation action in table.RiverActions)
					{
						TexasHoldemHandAction thhaction = new TexasHoldemHandAction(uow);
						thhaction.Street = PokerStreetType.River;
						thhaction.ActionNumber = actionNumber++;
						thhaction.ActionType = action.ActionType;
						thhaction.Amount = action.Amount;
						thhaction.HandId = summary.TexasHoldemHandSummaryId;
						thhaction.PlayerName = action.PlayerName;
						uow.MarkNew(thhaction);
					}
				if (table.ShowdownActions != null)
					foreach (TexasHoldemHandSummaryLegacy.ActionInformation action in table.ShowdownActions)
					{
						TexasHoldemHandAction thhaction = new TexasHoldemHandAction(uow);
						thhaction.Street = PokerStreetType.Showdown;
						thhaction.ActionNumber = actionNumber++;
						thhaction.ActionType = action.ActionType;
						thhaction.Amount = action.Amount;
						thhaction.HandId = summary.TexasHoldemHandSummaryId;
						thhaction.PlayerName = action.PlayerName;
						uow.MarkNew(thhaction);
					}
			}
			uow.Commit();

			DateTime end = DateTime.Now;

			TimeSpan duration = end.Subtract(start);
			System.Console.WriteLine(summaries.Count + " hands in " + duration + " (" + (int)(summaries.Count / duration.TotalSeconds) + " hands/sec, " + (int)(countLines / duration.TotalSeconds) + " line/sec).");

			System.Console.WriteLine("Analyzing datas ...");

			int wentToShowDown = 0;
			int total = 0;
			int tournament = 0;
			foreach (TexasHoldemHandSummary hand in commited)
			{
				if (hand.HasShowdown)
					wentToShowDown++;
				if (hand.TournamentId != null)
					tournament++;
				total++;
			}

			System.Console.WriteLine("Tournament: {0}/{1} ({2} %)", tournament, total, (tournament * 100.0 / total).ToString("0.00"));
			System.Console.WriteLine("Showdown: {0}/{1} ({2} %)", wentToShowDown, total, (wentToShowDown * 100.0 / total).ToString("0.00"));

			System.Console.ReadKey();
		}

		static void Main(string[] args)
		{
			ulong count = 0;
			foreach (ulong handMask in CardBit.TexasHoldemClosedCards())
				count++;

			System.Console.WriteLine(count + " possible two cards hand.");

			System.Console.ReadKey();
			return;
			/*
			ulong playerMask = CardSet.Parse("As Ks").Bitset;
			ulong board = CardSet.Parse("Ts Qs 2d").Bitset;

			double[] playerWins = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
			double[] opponentWins = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

			long count = 0;

			foreach (ulong opponentMask in CardBit.Hands(0, board | playerMask, 2))
			{
				foreach (ulong boardMask in CardBit.Hands(board, opponentMask | playerMask, 5))
				{
					uint playerHandValue = CardBit.Evaluate(boardMask | playerMask, 7);
					uint opponentHandValue = CardBit.Evaluate(boardMask | opponentMask, 7);

					if (playerHandValue > opponentHandValue)
						playerWins[CardBit.HandType(playerHandValue)] += 1;
					else if (playerHandValue < opponentHandValue)
						opponentWins[CardBit.HandType(opponentHandValue)] += 1;
					else
					{
						playerWins[CardBit.HandType(playerHandValue)] += 0.5;
						opponentWins[CardBit.HandType(opponentHandValue)] += 0.5;
					}
					count++;
				}
			}

			Array values = Enum.GetValues(typeof(PokerHandType));

			double playerTotalWins = 0;
			double opponentTotalWins = 0;
			string line;
			foreach (PokerHandType type in values)
			{
				int index =  values.Length - 1 - (int)type;
				line = string.Format("{0}\t{1} - {2}", type.ToString().PadRight(20, ' '), (playerWins[index] * 100 / count).ToString("0.00").PadLeft(6, ' '), (opponentWins[index] * 100 / count).ToString("0.00").PadLeft(6, ' '));
				playerTotalWins += playerWins[index];
				opponentTotalWins += opponentWins[index];
				Console.WriteLine(line);
			}
			Console.WriteLine(string.Empty.PadLeft(50, '-'));
			line = string.Format("{0}\t{1} - {2}", "Split/Win".PadRight(20, ' '), (playerTotalWins * 100 / count).ToString("0.00").PadLeft(6, ' '), (opponentTotalWins * 100 / count).ToString("0.00").PadLeft(6, ' '));
			Console.WriteLine(line);

			System.Console.ReadKey();
			return;

			PokerTable table = new PokerTable("OneTable", new PokerCashGameConfiguration(9, PokerLimit.NoLimit, PokerType.TexasHoldem, PokerCurrency.EUR, 0, 1, 2, 100, 400));
			PokerPlayer jonv11 = PokerPlayer.GetPlayer("jonv11", string.Empty, 1000, null);
			PokerPlayer niilzon = PokerPlayer.GetPlayer("niilzon", string.Empty, 1000, null);
			PokerPlayer vilain = PokerPlayer.GetPlayer("vilain", string.Empty, 1000, null);
			PokerPlayer hero = PokerPlayer.GetPlayer("hero", string.Empty, 1000, null);

			table.Sit(0, jonv11, 1000);
			table.Sit(1, niilzon, 1000);
			table.Sit(2, vilain, 1000);
			table.Sit(3, hero, 1000);

			TexasHoldemDealer dealer = new TexasHoldemDealer();
			table.Dealer = dealer;

			try
			{
				while (true)
					dealer.NextHand();
			}
			catch
			{
				System.Console.WriteLine("Table has been closed after {0} hands.", dealer.HandCount);
			}

			System.Console.ReadKey();
			return;
			*/
			ImportHandHistoryToDatabase(args);
		}

		private static int CompareStats(TexasHoldemPlayerStatistics a, TexasHoldemPlayerStatistics b)
		{
			return -a.HandCount.CompareTo(b.HandCount);
		}

	}
}
